home *** CD-ROM | disk | FTP | other *** search
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is QuickDrag.
- *
- * The Initial Developer of the Original Code is Kai Liu.
- * Portions created by the Initial Developer are Copyright (C) 2008-2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Kai Liu <kliu@code.kliu.org>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
- var QuickDragListener =
- {
- // The name of the event that we should listen to for drops
- _drop: "drop",
-
- handleEvent: function( evt )
- {
- var panel = gBrowser.mPanelContainer;
-
- switch (evt.type)
- {
- case "load":
- {
- // Prior to the landing of the WHATWG drag API in Gecko 1.9.1,
- // the event name was "dragdrop"
- if ("getDragData" in nsDragAndDrop)
- this._drop = "dragdrop";
-
- window.removeEventListener(evt.type, this, false);
- panel.addEventListener("dragstart", this, false);
- panel.addEventListener("dragover", this, false);
- panel.addEventListener(this._drop, this, false);
- break;
- }
-
- case "unload":
- {
- window.removeEventListener(evt.type, this, false);
- panel.removeEventListener("dragstart", this, false);
- panel.removeEventListener("dragover", this, false);
- panel.removeEventListener(this._drop, this, false);
- break;
- }
-
- case "dragstart":
- {
- QuickDrag.dragstart(evt);
- break;
- }
-
- case "dragover":
- {
- QuickDrag.dragover(evt);
- break;
- }
-
- case this._drop:
- {
- QuickDrag.dragdrop(evt);
- break;
- }
- }
- }
- };
-
- var QuickDrag =
- {
- /**
- * For a variety of reasons, the nsDragAndDrop JS wrapper is not suitable
- * for this extension, but there are some pieces of nsDragAndDrop that are
- * useful; these parts have been wrapped inside _session, _getDragData,
- * and _securityCheck.
- **/
-
- // We want to know the "true" source of the drag, which we can no longer
- // reliably get from the drag session in Gecko 1.9.1
- _sourceNode: null,
-
- // Wrapper for nsDragAndDrop.mDragSession
- get _session( )
- {
- if (!nsDragAndDrop.mDragSession)
- nsDragAndDrop.mDragSession = nsDragAndDrop.mDragService.getCurrentSession();
-
- return(nsDragAndDrop.mDragSession);
- },
-
- // Wrapper for nsDragAndDrop.js's data retrieval; see nsDragAndDrop.drop
- _getDragData: function( aEvent )
- {
- var data = "";
- var type = "text/unicode";
-
- if ("dataTransfer" in aEvent)
- {
- // Gecko 1.9.1 and newer: WHATWG drag-and-drop
-
- // Try to get text/x-moz-url, if possible
- data = aEvent.dataTransfer.getData("text/x-moz-url");
-
- if (data.length != 0)
- type = "text/x-moz-url";
- else
- data = aEvent.dataTransfer.getData("text/plain");
- }
- else if ("getDragData" in nsDragAndDrop)
- {
- // Gecko 1.9.0 and older: wrapper for nsDragAndDrop.getDragData
-
- var flavourSet = new FlavourSet();
- flavourSet.appendFlavour("text/x-moz-url");
- flavourSet.appendFlavour("text/unicode");
-
- var transferDataSet = nsTransferable.get(flavourSet, nsDragAndDrop.getDragData, true);
-
- data = transferDataSet.first.first.data;
- type = transferDataSet.first.first.flavour.contentType;
- }
-
- return({ data: data, type: type });
- },
-
- // Wrapper for nsDragAndDrop.dragDropSecurityCheck
- _securityCheck: function( aEvent, aDragSession, aDraggedText )
- {
- if ("dragDropSecurityCheck" in nsDragAndDrop)
- nsDragAndDrop.dragDropSecurityCheck(aEvent, aDragSession, aDraggedText);
- else if ("dragDropSecurityCheck" in gBrowser)
- gBrowser.dragDropSecurityCheck(aEvent, aDragSession, aDraggedText);
- },
-
- // Determine if two DOM nodes are from the same content area.
- _fromSameContentArea: function( node1, node2 )
- {
- return(
- node1 && node1.ownerDocument && node1.ownerDocument.defaultView &&
- node2 && node2.ownerDocument && node2.ownerDocument.defaultView &&
- node1.ownerDocument.defaultView.top.document ==
- node2.ownerDocument.defaultView.top.document
- );
- },
-
- // Is this an event that we want to handle?
- _shouldHandleEvent: function( evt )
- {
- return(
- ( this._session.isDataFlavorSupported("text/unicode") ||
- this._session.isDataFlavorSupported("text/plain") ) &&
- ( this._session.sourceNode == null ||
- this._fromSameContentArea(this._session.sourceNode, evt.target) )
- );
- },
-
- /**
- * Event handlers
- **/
-
- dragstart: function( evt )
- {
- this._sourceNode = evt.explicitOriginalTarget;
- },
-
- dragover: function( evt )
- {
- if (!this._shouldHandleEvent(evt)) return;
-
- this._session.canDrop = true;
- },
-
- dragdrop: function( evt )
- {
- if (!this._shouldHandleEvent(evt)) return;
-
- // Load preferences; note that the pref is FG, but the var is BG
- const prefs = Components.classes["@mozilla.org/preferences-service;1"].
- getService(Components.interfaces.nsIPrefService).
- getBranch("extensions.quickdrag.");
-
- var loadLinkInBG = !prefs.getBoolPref("loadLinkInFG") ^ evt.shiftKey;
- var loadSearchInBG = !prefs.getBoolPref("loadSearchInFG") ^ evt.shiftKey;
- var downloadImages = prefs.getBoolPref("downloadImages") || evt.altKey;
- var linkOpenOverride = prefs.getBoolPref("linkOpenOverride");
-
- // Get the source node and name
- var sourceNode = this._session.sourceNode;
-
- if (this._sourceNode)
- {
- sourceNode = this._sourceNode;
- this._sourceNode = null;
- }
-
- var sourceName = (sourceNode) ? sourceNode.nodeName : "";
-
- // Flags
- var isURI = false;
- var isImage = false;
- var isAnchorLink = false;
-
- // Parse the drag data
- var dragData = this._getDragData(evt);
- var lines = dragData.data.replace(/^\s+|\s+$/g, "").split(/\s*\n\s*/);
- var str = lines.join(" ");
-
- if (dragData.type == "text/x-moz-url")
- {
- // The user has dragged either a link or an image
-
- // By default, we want to use the URI (the first line)
- str = lines[0];
- isURI = true;
-
- if (sourceName == "IMG")
- {
- // Image or image link
- isImage = true;
-
- // If the URI does not match the source node, then this is a
- // linked image (note that we DO want to treat images linked to
- // themselves as if they are not linked at all)
- if (sourceNode.src != str)
- isAnchorLink = true;
- }
- else if (sourceName == "#text")
- {
- // Text link
- isAnchorLink = true;
-
- // The link's content text, condensed into one line
- var text = lines.slice(1).join(" ");
-
- // If appropriate, use the content text instead of the URI
- if (!linkOpenOverride && text)
- {
- str = text;
- isURI = false;
- }
- }
- }
-
- // Abort if we have no data; otherwise, proceed with URI detection
- if (!str) return;
-
- // Our heuristics; see bug 58 for info about the http fixup
- var hasScheme = /^(?:(?:h?tt|hxx)ps?|ftp|chrome|file):\/\//i;
- var hasIP = /(?:^|[\/@])(?:\d{1,3}\.){3}\d{1,3}(?:[:\/\?]|$)/;
- var hasDomain = new RegExp(
- // starting boundary
- "(?:^|[:\\/\\.@])" +
- // valid second-level name
- "[a-z0-9](?:[a-z0-9-]*[a-z0-9])" +
- // valid top-level name: ccTLDs + hard-coded [gs]TLDs
- "\\.(?:[a-z]{2}|aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel)" +
- // end boundary
- "(?:[:\\/\\?]|$)",
- // ignore case
- "i"
- );
-
- isURI = isURI || hasScheme.test(str);
- isURI = isURI || (!/\s/.test(str) && (hasIP.test(str) || hasDomain.test(str)));
-
- if (isURI)
- {
- // The scheme fixup here is more relaxed; patterns that match this
- // fixup but that failed the initial scheme heuristic are those
- // that match a valid domain or IP address pattern
- str = str.replace(/^(?:t?t|h[tx]{2,})p(s?:\/\/)/i, "http$1");
-
- // Call dragDropSecurityCheck
- this._securityCheck(evt, this._session, str);
-
- // Treat drag as a middle click?
- var mimicMiddleClick = isAnchorLink && linkOpenOverride;
-
- // Send the referrer only for embedded images or emulated
- // middle clicks over HTTP/HTTPS
- var referrer = null;
-
- if (sourceNode)
- {
- referrer = Components.classes["@mozilla.org/network/io-service;1"].
- getService(Components.interfaces.nsIIOService).
- newURI(sourceNode.ownerDocument.location.href, null, null);
-
- if (!((isImage || mimicMiddleClick) && /^https?$/i.test(referrer.scheme)))
- referrer = null;
- }
-
- // Turn naked e-mail addresses into mailto: links
- if (/^[\w\.\+\-]+@[\w\.\-]+\.[\w\-]{2,}$/.test(str))
- str = "mailto:" + str;
-
- // For image links, the we want to use the source URL unless we
- // are going to treat the image as a link
- if (isImage && (!mimicMiddleClick || evt.ctrlKey))
- str = sourceNode.src;
-
- if (isImage && !mimicMiddleClick && !evt.ctrlKey && downloadImages)
- this._saveImage(str, referrer);
- else if (!evt.altKey || (isImage && evt.ctrlKey) || !this._saveURL(str, referrer))
- this._loadTab(str, referrer, null, loadLinkInBG);
- }
- else if (this._isSuite)
- {
- // Suite search
- OpenSearch('qdsearch', str, true, evt.shiftKey);
- }
- else
- {
- // Firefox search
- // Based on BrowserSearch::loadSearch in browser.js
-
- const ss = Components.classes["@mozilla.org/browser/search-service;1"].
- getService(Components.interfaces.nsIBrowserSearchService);
-
- // Test to see if the search bar is active
- var searchBarActive = false;
- var searchBar = document.getElementById("searchbar");
- if (searchBar)
- {
- var style = window.getComputedStyle(searchBar.parentNode, null);
- if (style.visibility == "visible" && style.display != "none")
- searchBarActive = true;
- }
-
- // If the search bar is visible, use the current engine;
- // otherwise, fall back to the default engine
- var engine = (searchBarActive) ? ss.currentEngine : ss.defaultEngine;
- var submission = engine.getSubmission(str, null);
-
- // Open the search in a new tab
- this._loadTab(submission.uri.spec, null, submission.postData, loadSearchInBG);
- }
-
- evt.preventDefault();
- evt.stopPropagation();
- },
-
- /**
- * SeaMonkey compatibility
- **/
-
- // 0 == unknown, 1 == default (Firefox), 2 == suite (SeaMonkey)
- _browserType: 0,
-
- // true == SeaMonkey, false == Firefox
- get _isSuite( )
- {
- if (this._browserType == 0)
- {
- const xai = Components.classes["@mozilla.org/xre/app-info;1"].
- getService(Components.interfaces.nsIXULAppInfo);
-
- // Cache the result
- this._browserType = (xai.ID == "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}") ? 2 : 1;
- }
-
- return(this._browserType == 2);
- },
-
- // Wrapper for loadOneTab/addTab
- _loadTab: function( aURI, aReferrerURI, aPostData, aLoadInBackground )
- {
- if (this._isSuite)
- gBrowser.addTab(aURI, aReferrerURI, null, !aLoadInBackground, 0);
- else
- gBrowser.loadOneTab(aURI, aReferrerURI, null, aPostData, aLoadInBackground, false);
- },
-
- // Wrapper for saveURL
- _saveURL: function( aURL, aReferrer )
- {
- // Unlike _loadTab, we need to do the scheme fixup manually; the "." is
- // omitted because example.org:80 is probably server:80, not scheme:80
- if (!/^[a-z][\da-z+\-]*:/i.test(aURL))
- aURL = aURL.replace(/^:*[\/\\\s]*/, "http://").replace(/^ht(tp:\/\/ftp\.)/i, "f$1");
-
- // If the protocol is not supported, let it fall through to a new tab
- if (!/^(?:https?|ftp):/i.test(aURL))
- return(false);
-
- if (this._isSuite)
- saveURL(aURL, null, null, false, aReferrer);
- else
- saveURL(aURL, null, null, false, true, aReferrer);
-
- return(true);
- },
-
- // Wrapper for saveImageURL
- _saveImage: function( aURL, aReferrer )
- {
- if (this._isSuite)
- saveImageURL(aURL, null, null, false, aReferrer);
- else
- saveImageURL(aURL, null, null, false, true, aReferrer);
- }
- };
-
- window.addEventListener("load", QuickDragListener, false);
- window.addEventListener("unload", QuickDragListener, false);
-